package com.radar.io.radar346;

import cn.hutool.core.date.DateUtil;
import com.radar.algorithm.Cacl;
import com.radar.algorithm.MathCommon;
import com.radar.common.DateConstants;
import com.radar.common.GisConstants;
import com.radar.common.ProductType;
import com.radar.exception.RadarCaclError;
import com.radar.exception.RadarDecodeError;
import com.radar.exception.RadarVisualizeError;
import com.radar.io.BaseRadr;
import com.radar.io.RadarGridData;
import com.radar.io.radar346.DataType.*;
import com.radar.utils.BitConverter;
import com.radar.visualize.PolarMap;
import com.radar.visualize.RasterMap;
import com.radar.visualize.ThematicMap;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;

public class Product382改 extends BaseRadr {

    @Override
    public void dispose() {

    }

    //region 原始数据文件

    //站址段 160
    public class RealAddrSec {

        //!< 文件头长度 ** 【2】
        short HeadLen;
        //!< 国名  【20】
        String Nation;
        //!< 省名  【20】
        String State;
        //!< 区名  【20】
        String Station;
        //!< 区站名  【20】
        String SectionSta;
        //!< 文件格式版本号 [4 - 7]存放数据来源 【20】
        String Type;
        //!< 格式E15度32'12"  【20】
        String Longitude;
        //!< 格式N35度30'15"  【20】
        String Latitude;
        //!< 天线所在径度的数值表示，单位取1／1000度(东经为整，西径为负)   **  【4】
        double LongitudeV;
        //!< 天线所在纬度的数值表示，单位取1／1000度(北纬为正，南纬为负)   **  【4】
        double LatitudeV;
        //!< 天线所在的海拔高度，以mm为单位                                **  【4】
        int Height;
        //!< 测站四周地物的最大仰角(以百分之一度为单位)  【2】
        int Elevation;
        //!< 测站的最佳观测仰角(地物回波强度10dbz)，以百分之一度为单位  【2】
        int Elevation1;
        //!< 站点编号  【2】
        int Category;

        int size = 160;

        public void parse(byte[] b) {
            int index = 0;
            HeadLen = BitConverter.toInt16(b, index);
            index += 2;
            Nation = new String(Arrays.copyOfRange(b, index, index + 20));
            index += 20;
            State = new String(Arrays.copyOfRange(b, index, index + 20));
            index += 20;
            Station = new String(Arrays.copyOfRange(b, index, index + 20));
            index += 20;
            SectionSta = new String(Arrays.copyOfRange(b, index, index + 20));
            index += 20;
            Type = new String(Arrays.copyOfRange(b, index, index + 20));
            index += 20;
            Longitude = new String(Arrays.copyOfRange(b, index, index + 20));
            index += 20;
            Latitude = new String(Arrays.copyOfRange(b, index, index + 20));
            index += 20;
            LongitudeV = BitConverter.toInt32(b, index) / 360000.0;
            index += 4;
            LatitudeV = BitConverter.toInt32(b, index) / 360000.0;
            index += 4;
            Height = BitConverter.toInt32(b, index);
            index += 4;
            Elevation = BitConverter.toInt16(b, index);
            index += 2;
            Elevation1 = BitConverter.toInt16(b, index);
            index += 2;
            Category = BitConverter.toInt16(b, index);
            index += 2;
        }
    }

    //性能参数段 40
    public class RealCapabilitySec {
        int antennaG;                //天线增益,以0.01dB为计数单位
        int beamH;            //垂直波束宽度 单位取百分之一度
        int beamL;            //!< 水平波束宽度  单位取百分之一度     **  【2】
        int polarizations;     //极化状况 0=水平，  1=垂直， 2=双偏振，3=圆偏振，4=其他
        int sidelobe;              //!< 第一旁瓣电平，取绝对值（单位取百分之一dB）  【2】
        int wavelength;        //!< 波长，以微米为单位          **  【2】
        int power;            //!< 雷达峰值功率，以瓦为单位  【4】
        int logA;       //!< 对数接收机动态范围，以百分之一dB为单位  【2】
        int LineA;      //!< 线性接收机动态范围，以百分之一dB为单位  【2】
        int AGCP;       //!< AGC延迟量，以微秒为单位  【2】
        int iDuShuZuiXiaoGongLv;    //!< 对数接收机最小可测功率，以百分之一dbmw为单位  【2】
        int iXianXingZuiXiaoGongLv;   //!< 线性接收机最小可测功率，以百分之一dbmw为单位  【2】
        int iZaoShengYuZhi;    //!< 噪声消除的量化阀值（0-255）  【2】
        int iDuoPoLeXiao;     //!< 多普勒杂波消除阀值，单位0.01db  【2】
        int sQIT;       //!< SQI阀值（0-1）：实际值乘1000  【2】
        int iSuDuChuLiFangShi; /*! 速度处理方式   【2】
                                             0:无速度处理；
                                             1:PPI；
                                             2:FFT；
                                            */
        int iDiWuChuLiFangShi; /*! 地物处理方式  【2】
                                             - 0:无地物处理；
                                             - 1:地物杂波图扣除法；
                                             - 2:滤波器处理；
                                             - 3:滤波器＋地物杂波图法；
                                             - 4:谱分析法
                                            */
        int iQiangDuTongDao;   /*! 强度估算采用的通道  【2】
                                             - 1:对数;
                                             - 2:线性
                                            */
        int iJuLiDingZheng;    //!< 【2】
        int size = 40;

        public void parse(byte[] b) {
            int index = 0;
            antennaG = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            beamH = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            beamL = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            polarizations = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            sidelobe = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            wavelength = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            power = BitConverter.toInt32(b, index);
            index += 4;
            logA = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            LineA = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            AGCP = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            iDuShuZuiXiaoGongLv = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            iXianXingZuiXiaoGongLv = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            iZaoShengYuZhi = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            iDuoPoLeXiao = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            sQIT = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            iSuDuChuLiFangShi = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            iDiWuChuLiFangShi = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            iQiangDuTongDao = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            iJuLiDingZheng = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
        }

    }

    //观测参数段 1066
    public class RealObserSec {
        public int iProductNumber;	/*! 产品编号 <0>        **  【2】
                                             - 0:PPI1
                                             - 1:RHI
                                             - 2:立体扫描
                                             - 3.反射率
                                             - 4.速度
                                             - 5.谱宽
                                            */
        public int iLiTiSaoMiaoCengShu;    //!< 立体扫描层数（PHI扫描填零，PPI扫描时填1）<2> **  【2】
        int iGuanCeKaiShiNian;        //!< 观测开始时间 年（4位数如2000）	<4>  【2】
        int iGuanCeKaiShiYue;        //!< 观测开始时间 月（01-12）<6>  【2】
        int iGuanCeKaiShiRi;        //!< 观测开始时间 日（01-31）  【2】
        int iGuanCeKaiShiShi;        //!< 观测开始时间 小时（00-23）  【2】
        int iGuanCeKaiShiFen;        //!< 观测开始时间 分（00-59）  【2】
        int iGuanCeKaiShiMiao;        //!< 观测开始时间 秒（00-59）  【2】
        int iKaiShiGPSShiJian;        //!< 开始GPS时间(无GPS填零)  【4】
        int iDingBiaoQingKuang;	/*! 定标情况  【2】
                                                 - 0:没有定标
                                                 - 1:自动定标
                                                 - 2:一周内人工定标
                                                 - 3:一月内人工定标
                                                */
        int iQianDuJiFenCiShu;        //!< 强度积分次数  【2】
        int iSuDuChuLiShu;            //!< 速度处理样本数  【2】
        public LayerParam[] LayerParam = new LayerParam[30];

        byte cShuJuPaiLieFangShi;		/*! 一个径向中的数据排列方式      ** 【1】
                                        - 11按库排列：库中先速度后强度（两要素）
                                        - 12按库排列：库中先强度后速度（两要素）
                                        - 13按库排列：库中先速度后谱宽（两要素）
                                        - 14按库排列：库中先速度后强度再谱宽
                                        - 15按库排列：库中先强度后速度再谱宽
                                        - 21按要素排列：单强度,地物滤波( ConR )
                                        - 22按要素排列：单速度( V )
                                        - 23按要素排列：先强度后速度( ConR + V )
                                        - 24按要素排列：先速度后强度( V + ConR )
                                        - 25按要素排列：先速度后谱宽( V + W )
                                        - 26按要素排列：先速度后强度再谱宽( V + ConR + W )
                                        - 27按要素排列：先强度后速度再谱宽( ConR + V + W )
                                        - 31 346-S, 按要素排列:  ConR
                                        - 32 346-S, 按要素排列:  R
                                        - 33 346-S, 按要素排列:  ConR + R
                                        - 34 346-S, 按要素排列:  ConR + V + W
                                        - 35 346-S, 按要素排列:  R + V + W
                                        - 36 346-S, 按要素排列:  ConR + R + V + W
                                    */
        byte cQiangDuZiJieShu;	/*! 一个强度数据占用的字节数，百位数表示  【1】
                                     - 是否有符号位，
                                      -#  Oxx：表示不无符号位；
                                      -# 1xx：表示有符号位
                                    */
        byte cSuDuZiJieShu;	/*! 一个速度数据占用的字节数，百位数表示是否有符号位  【1】
                                     - Oxx：表示无符号位；
                                     - 1xx：表示有符号位。
                                    */
        byte cPuKuanZiJieShu;	/*! 一个谱宽数据占用的字节f数，百位数表示是否有符号位  【1】
                                     - 0:表示不无符号位；
                                     - 1:表示有符号位。
                                    */
        int iQiangDuWuHuiBoMa;    //!< 强度：无回波的代表码        **  【2】
        int iSuDuWuHuiBoMa;        //!< 速度：无回波的代表码  【2】
        int iPuKuanWuHuiBoMa;        //!< 谱宽：无回波的代表码  【2】
        int iQiangDuZengLiang;    //!< 数据中的强度最小增量01000  【2】
        int iSuDuZengLiang;        //!< 数据中的速度最小增量*1000  【2】
        int iPuKuanZengLiang;        //!< 数据中的谱宽最小增量*1000  【2】
        int iQiangDu0;        //!< 强度：如果用无符号类型数表示，填写代表零的数值  【2】
        int iSuDu0;        //!< 速度：如果用无符号类型数表示，填写代表零的数值  【2】
        int iPuKuan0;        //!< 谱宽：如果用无符号类型数表示，填写代表零的数值  【2】
        int iGuanCeJieSuNian;    //!< 观测结束时间，年(四位数)  【2】
        int iGuanCeJieSuYue;    //!< 观测结束时间，月(1-12)  【2】
        int iGuanCeJieSuRi;    //!< 观测结束时间，日(1-31)  【2】
        int iGuanCeJieSuShi;    //!< 观测结束时间，时(00-23)  【2】
        int iGuanCeJieSuFen;    //!< 观测结束时间，分(00-59)  【2】
        int iGuanCeJieSuMiao;    //!< 观测结束时间，秒(00-59)  【2】
        long iJieSuGPSShiJian;    //!< GPS时间(无GPS填零)  【4】
        int iJieGou1DaXiao;    //!< 应写注结构(1)数组的大小。 【2】

        public void parse(byte[] b) {
            int index = 0;
            iProductNumber = Short.toUnsignedInt(BitConverter.toInt16(b, index));
            index += 2;
            iLiTiSaoMiaoCengShu = Short.toUnsignedInt(BitConverter.toInt16(b, index));
            index += 2;
            iGuanCeKaiShiNian = Short.toUnsignedInt(BitConverter.toInt16(b, index));
            index += 2;
            iGuanCeKaiShiYue = Short.toUnsignedInt(BitConverter.toInt16(b, index));
            index += 2;
            iGuanCeKaiShiRi = Short.toUnsignedInt(BitConverter.toInt16(b, index));
            index += 2;
            iGuanCeKaiShiShi = Short.toUnsignedInt(BitConverter.toInt16(b, index));
            index += 2;
            iGuanCeKaiShiFen = Short.toUnsignedInt(BitConverter.toInt16(b, index));
            index += 2;
            iGuanCeKaiShiMiao = Short.toUnsignedInt(BitConverter.toInt16(b, index));
            index += 2;
            iKaiShiGPSShiJian = BitConverter.toInt32(b, index);
            index += 4;
            iDingBiaoQingKuang = Short.toUnsignedInt(BitConverter.toInt16(b, index));
            index += 2;
            iQianDuJiFenCiShu = Short.toUnsignedInt(BitConverter.toInt16(b, index));
            index += 2;
            iSuDuChuLiShu = Short.toUnsignedInt(BitConverter.toInt16(b, index));
            index += 2;
            IntStream.range(0, 30).forEach(i -> LayerParam[i] = new LayerParam());
            AtomicInteger finalIndex = new AtomicInteger(index);
            IntStream.range(0, 30).forEach(i -> LayerParam[i].id = BitConverter.toInt32(b, finalIndex.intValue() + i * 4));
            finalIndex.set(finalIndex.intValue() + 120);
            IntStream.range(0, 30).forEach(i -> LayerParam[i].cGuanCeYaoSu = b[finalIndex.intValue() + i]);
            finalIndex.set(finalIndex.intValue() + 30);
            IntStream.range(0, 30).forEach(i -> LayerParam[i].cSuDuTuiMoFu = b[finalIndex.intValue() + i]);
            finalIndex.set(finalIndex.intValue() + 30);
            IntStream.range(0, 30).forEach(i -> LayerParam[i].iYiMaiChongChongPin = Short.toUnsignedInt(BitConverter.toInt16(b, finalIndex.intValue() + i * 2)));
            finalIndex.set(finalIndex.intValue() + 60);
            IntStream.range(0, 30).forEach(i -> LayerParam[i].iErMaiChongChongPin = Short.toUnsignedInt(BitConverter.toInt16(b, finalIndex.intValue() + i * 2)));
            finalIndex.set(finalIndex.intValue() + 60);
            IntStream.range(0, 30).forEach(i -> LayerParam[i].iMaiChongKuanDu = Short.toUnsignedInt(BitConverter.toInt16(b, finalIndex.intValue() + i * 2)));
            finalIndex.set(finalIndex.intValue() + 60);
            IntStream.range(0, 30).forEach(i -> LayerParam[i].iZuiDaCeSu = Short.toUnsignedInt(BitConverter.toInt16(b, finalIndex.intValue() + i * 2)));
            finalIndex.set(finalIndex.intValue() + 60);
            IntStream.range(0, 30).forEach(i -> LayerParam[i].usRefBinNumber = Short.toUnsignedInt(BitConverter.toInt16(b, finalIndex.intValue() + i * 2)));
            finalIndex.set(finalIndex.intValue() + 60);
            IntStream.range(0, 30).forEach(i -> LayerParam[i].iCaiYangJinXiangShu = Short.toUnsignedInt(BitConverter.toInt16(b, finalIndex.intValue() + i * 2)));
            finalIndex.set(finalIndex.intValue() + 60);
            IntStream.range(0, 30).forEach(i -> LayerParam[i].iJinXiangKuShu = Short.toUnsignedInt(BitConverter.toInt16(b, finalIndex.intValue() + i * 2)));
            finalIndex.set(finalIndex.intValue() + 60);
            IntStream.range(0, 30).forEach(i -> LayerParam[i].iKuChang = Short.toUnsignedInt(BitConverter.toInt16(b, finalIndex.intValue() + i * 2)));
            finalIndex.set(finalIndex.intValue() + 60);
            IntStream.range(0, 30).forEach(i -> LayerParam[i].iDiYiKuJuLi = BitConverter.toInt32(b, finalIndex.intValue() + i * 4));
            finalIndex.set(finalIndex.intValue() + 120);
            IntStream.range(0, 30).forEach(i -> LayerParam[i].iPPIKaiShiWeiZhi = Short.toUnsignedInt(BitConverter.toInt16(b, finalIndex.intValue() + i * 2)));
            finalIndex.set(finalIndex.intValue() + 60);
            IntStream.range(0, 30).forEach(i -> LayerParam[i].iYangJiao = BitConverter.toInt16(b, finalIndex.intValue() + i * 2));
            index = finalIndex.intValue() + 60;
            cShuJuPaiLieFangShi = b[index];
            index++;
            cQiangDuZiJieShu = b[index];
            index++;
            cSuDuZiJieShu = b[index];
            index++;
            cPuKuanZiJieShu = b[index];
            index++;
            iQiangDuWuHuiBoMa = BitConverter.toInt16(b, index);
            index += 2;
            iSuDuWuHuiBoMa = BitConverter.toInt16(b, index);
            index += 2;
            iPuKuanWuHuiBoMa = BitConverter.toInt16(b, index);
            index += 2;
            iQiangDuZengLiang = BitConverter.toInt16(b, index);
            index += 2;
            iSuDuZengLiang = BitConverter.toInt16(b, index);
            index += 2;
            iPuKuanZengLiang = BitConverter.toInt16(b, index);
            index += 2;
            iQiangDu0 = BitConverter.toInt16(b, index);
            index += 2;
            iSuDu0 = BitConverter.toInt16(b, index);
            index += 2;
            iPuKuan0 = BitConverter.toInt16(b, index);
            index += 2;
            iGuanCeJieSuNian = Short.toUnsignedInt(BitConverter.toInt16(b, index));
            index += 2;
            iGuanCeJieSuYue = Short.toUnsignedInt(BitConverter.toInt16(b, index));
            index += 2;
            iGuanCeJieSuRi = Short.toUnsignedInt(BitConverter.toInt16(b, index));
            index += 2;
            iGuanCeJieSuShi = Short.toUnsignedInt(BitConverter.toInt16(b, index));
            index += 2;
            iGuanCeJieSuFen = Short.toUnsignedInt(BitConverter.toInt16(b, index));
            index += 2;
            iGuanCeJieSuMiao = Short.toUnsignedInt(BitConverter.toInt16(b, index));
            index += 2;
            iJieSuGPSShiJian = Integer.toUnsignedLong(BitConverter.toInt32(b, index));
            index += 4;
            iJieGou1DaXiao = Short.toUnsignedInt(BitConverter.toInt16(b, index));
            index += 2;

        }
    }

    public class LayerParam {
        int id;
        byte cGuanCeYaoSu;
        int cSuDuTuiMoFu;
        int iYiMaiChongChongPin;
        int iErMaiChongChongPin;
        int iMaiChongKuanDu;
        int iZuiDaCeSu;
        public int usRefBinNumber;
        public int iCaiYangJinXiangShu;
        public int iJinXiangKuShu;
        int iKuChang;
        int iDiYiKuJuLi;
        int iPPIKaiShiWeiZhi;
        int iYangJiao;
    }

    public class RealFile {
        int size = 1266;
        // 160
        public RealAddrSec realAddrSec;
        // 40
        public RealCapabilitySec realCapabilitySec;
        // 1066
        public RealObserSec realObserSec;

        public void parse(byte[] b) {
            int index = 0;
            byte[] bytdata = new byte[160];
            System.arraycopy(b, index, bytdata, 0, bytdata.length);
            realAddrSec = new RealAddrSec();
            realAddrSec.parse(bytdata);
            index += 160;

            bytdata = new byte[40];
            System.arraycopy(b, index, bytdata, 0, bytdata.length);
            realCapabilitySec = new RealCapabilitySec();
            realCapabilitySec.parse(bytdata);
            index += 40;

            bytdata = new byte[1066];
            System.arraycopy(b, index, bytdata, 0, bytdata.length);
            realObserSec = new RealObserSec();
            realObserSec.parse(bytdata);
            index += 40;
//            bytdata = new byte[516];
//            System.arraycopy(b, index, bytdata, 0, bytdata.length);
//            radarObservationInfo = new RadarObservationParamA();
//            radarObservationInfo.parse(bytdata);
//            index += 516;
//            Reserved = new byte[24];
//            System.arraycopy(b, index, Reserved, 0, 24);
//            index += 24;
        }
    }

    public class RadialHeader {
        public int len = 64;
        private int radialState;
        private int spotBlank;
        private int seqNumber;
        private int radialNumber;
        private int elevationNumber;
        public double azimuth;
        private double elevation;
        private int seconds;
        private int microseconds;
        private int dataLength;
        private int momentNumber;
        private int res5;
        private int horiEstNoise;
        private int vertEstNoise;
        private String zipType;
        private String res6;

        public void parse(byte[] b) throws Exception {
            int index = 0;
//            radialState = BitConverter.toInt32(b, index);
//            index += 4;
//            spotBlank = BitConverter.toInt32(b, index);
//            index += 4;
//            seqNumber = BitConverter.toInt32(b, index);
//            index += 4;
//            radialNumber = BitConverter.toInt32(b, index);
//            index += 4;
//            elevationNumber = BitConverter.toInt32(b, index);
//            index += 4;
            index += 4;
            azimuth = Short.toUnsignedInt(BitConverter.toInt16(b, index)) / 100.0;
            index += 2;
            elevation = Short.toUnsignedInt(BitConverter.toInt16(b, index)) / 100.0;
            index += 2;

//            seconds = BitConverter.toInt32(b, index);
//            index += 4;
//            microseconds = BitConverter.toInt32(b, index);
//            index += 4;
//            dataLength = BitConverter.toInt32(b, index);
//            index += 4;
//            momentNumber = BitConverter.toInt32(b, index);
//            index += 4;
//
//            res5 = (BitConverter.toInt16(b, index) & 0x0FFFF);
//            index += 2;
//            horiEstNoise = (BitConverter.toInt16(b, index) & 0x0FFFF);
//            index += 2;
//            vertEstNoise = (BitConverter.toInt16(b, index) & 0x0FFFF);
//            index += 2;
//            zipType = BitConverter.toString(Arrays.copyOfRange(b, index, index + 1));
//            index += 1;
//            zipType = zipType.replace("\u0000", "");
//            res6 = BitConverter.toString(Arrays.copyOfRange(b, index, index + 13));
//            index += 13;
        }
    }

    public class RadarObservationParamA {
        public byte SType;
        public byte WeatherMode;
        public int SYear;
        public byte SMonth;
        public byte SDay;
        public byte SHour;
        public byte SMinute;
        public byte SSecond;
        public byte Calibration;
        public byte LayerNum;
        // 19
        public LayerParamA[] LayerParam;
        public int RHIA;
        public short RHIL;
        public short RHIH;
        public byte[] Reserved;

        public void parse(byte[] b) {
            int index = 0;
            SType = b[index];
            index++;
            WeatherMode = b[index];
            index++;
            SYear = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            SMonth = b[index];
            index++;
            SDay = b[index];
            index++;
            SHour = b[index];
            index++;
            SMinute = b[index];
            index++;
            SSecond = b[index];
            index++;
            Calibration = b[index];
            index++;
            LayerNum = b[index];
            index++;
            LayerParam = new LayerParamA[25];
            for (int i = 0; i < LayerParam.length; i++) {
                byte[] bytdata = new byte[19];
                System.arraycopy(b, index, bytdata, 0, bytdata.length);
                LayerParam[i] = new LayerParamA();
                LayerParam[i].parse(bytdata);
                index += 19;
            }
            RHIA = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            RHIL = BitConverter.toInt16(b, index);
            index += 2;
            RHIH = BitConverter.toInt16(b, index);
            index += 2;
            Reserved = new byte[24];
            System.arraycopy(b, index, Reserved, 0, 24);
        }
    }

    public class LayerParamA {
        public byte Ambiguousp;
        public int PRF1;
        public int PRF2;
        public byte Filter;
        public int PluseW;
        public int MaxV;
        public int MaxL;
        public int BinWidth;
        public int BinNumber;
        public int RecodeNumber;
        public int DataForm;

        public void parse(byte[] b) {
            int index = 0;
            Ambiguousp = b[index];
            index++;
            PRF1 = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            PRF2 = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            Filter = b[index];
            index++;
            PluseW = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            MaxV = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            MaxL = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            BinWidth = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            BinNumber = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            RecodeNumber = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            DataForm = (0xff & b[index]);
            index++;
        }
    }

    public class lineDataBlock {
        public short Elevation;
        public int Azimuth;
        public String Longitude;
        public String Latitude;
        public float Vs;
        public float Hs;
        public int Course;
        public int Nv;
        public byte[] CorZ;
        public byte[] UnZ;
        public int[] V;
        public byte[] W;

        public void parse(byte[] b) {
            int index = 0;
            Elevation = BitConverter.toInt16(b, index);
            index += 2;
            Azimuth = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            Longitude = new String(Arrays.copyOfRange(b, index, index + 16));
            index += 16;
            Latitude = new String(Arrays.copyOfRange(b, index, index + 16));
            index += 16;
            Vs = BitConverter.toSingle(b, index);
            index += 4;
            Hs = BitConverter.toSingle(b, index);
            index += 4;
            Course = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            Nv = (BitConverter.toInt16(b, index) & 0x0FFFF);
            index += 2;
            CorZ = new byte[1024];
            System.arraycopy(b, index, CorZ, 0, CorZ.length);
            index += 1024;
            UnZ = new byte[1024];
            System.arraycopy(b, index, UnZ, 0, UnZ.length);
            index += 1024;
            V = new int[1024];
            byte[] bytdata = new byte[1024];
            System.arraycopy(b, index, bytdata, 0, bytdata.length);
            for (int i = 0; i < V.length; i++) {
                V[i] = (0xff & bytdata[i]);
            }
            index += 1024;
            W = new byte[1024];
            System.arraycopy(b, index, W, 0, W.length);
            index += 1024;
        }
    }
    //endregion

    public int Bins;

    public int BinLength;

    public int Records;

    public double MaxL;

    public double[] azi;

    public double ele;

    public double[][] data;

    public double[][][] data3d;

    public double lon;

    public double lat;

    public Date dateTime;

    public RealFile header;

    public VWP vwp;
    public VAD vad;

    public ProductType parseProduct(String file) throws RadarDecodeError {
        ProductType productType = null;
        super.parse(file);
        RealFile header = new RealFile();
        int hLen = header.size;
        int index = 0;
        byte[] bytdata = new byte[hLen];
        try {
            System.arraycopy(bytes, index, bytdata, 0, bytdata.length);
            index += bytdata.length;
            header.parse(bytdata);
            this.header = header;
            if (this.header.realObserSec.iProductNumber == 3) {
                // SUCCESS
                productType = ProductType.REF;
            } else if (this.header.realObserSec.iProductNumber == 4) {
                // SUCCESS
                productType = ProductType.VEL;
            } else if (this.header.realObserSec.iProductNumber == 5) {
                // SUCCESS
                productType = ProductType.SW;
            } else if (this.header.realObserSec.iProductNumber == 6) {
                // SUCCESS
                productType = ProductType.ET;
            } else if (this.header.realObserSec.iProductNumber == 7) {
                // SUCCESS
                productType = ProductType.EB;
            } else if (this.header.realObserSec.iProductNumber == 8) {
                // SUCCESS
                productType = ProductType.CAPPI;
            } else if (this.header.realObserSec.iProductNumber == 9) {
                // SUCCESS
                productType = ProductType.RCS;
            } else if (this.header.realObserSec.iProductNumber == 10) {
                // SUCCESS
                productType = ProductType.CR;
            } else if (this.header.realObserSec.iProductNumber == 24) {
                // SUCCESS
                productType = ProductType.VAD;
            } else if (this.header.realObserSec.iProductNumber == 25) {
                // SUCCESS
                productType = ProductType.VIL;
            } else if (this.header.realObserSec.iProductNumber == 26) {
                // SUCESSC
                productType = ProductType.LRA;
            } else if (this.header.realObserSec.iProductNumber == 27) {
                // SUCCESS
                productType = ProductType.LRM;
            } else if (this.header.realObserSec.iProductNumber == 28) {
                // SUCCESS
                productType = ProductType.VCS;
            } else if (this.header.realObserSec.iProductNumber == 32) {
                // SUCCESS 纯数据
                productType = ProductType.VWP;
            } else if (this.header.realObserSec.iProductNumber == 39) {
                // SUCCESS ?雨强
                productType = ProductType.OHP;
            } else if (this.header.realObserSec.iProductNumber == 42) {
                // SUCCESS 合成切边单位 E-4/S
                productType = ProductType.CS;
            } else if (this.header.realObserSec.iProductNumber == 43) {
                // SUCCESS 方位涡度 E-2/S  * 100 之后的数值 采用速度图例
                productType = ProductType.ARD;
            } else if (this.header.realObserSec.iProductNumber == 44) {
                // SUCCESS 径向散度单位 E-2/S  * 100 之后的数值 采用速度图例
                productType = ProductType.RVD;
            } else if (this.header.realObserSec.iProductNumber == 52) {
                // SUCCESS
                productType = ProductType.REF;
            } else if (this.header.realObserSec.iProductNumber == 54) {
                // SUCCESS 一小时降水 NHP
                productType = ProductType.OHP;
            } else if (this.header.realObserSec.iProductNumber == 49) {
                // TODO 文档错误
                productType = ProductType.STI;
            } else {
                return null;
            }
            GregorianCalendar gc = new GregorianCalendar();
            String format = header.realObserSec.iGuanCeKaiShiNian + "-" + (header.realObserSec.iGuanCeKaiShiYue < 10 ? "0" + header.realObserSec.iGuanCeKaiShiYue : header.realObserSec.iGuanCeKaiShiYue) + "-" + (header.realObserSec.iGuanCeKaiShiRi < 10 ? "0" + header.realObserSec.iGuanCeKaiShiRi : header.realObserSec.iGuanCeKaiShiRi);
            Date date = DateUtil.parse(format, DateConstants.DATE_FORMAT_YY_MM_DD);
            gc.setTime(date);
            gc.set(GregorianCalendar.HOUR_OF_DAY, header.realObserSec.iGuanCeKaiShiShi);
            gc.set(GregorianCalendar.MINUTE, header.realObserSec.iGuanCeKaiShiFen);
            gc.set(GregorianCalendar.SECOND, header.realObserSec.iGuanCeKaiShiMiao);
            lon = header.realAddrSec.LongitudeV;
            lat = header.realAddrSec.LatitudeV;
            dateTime = gc.getTime();
            int Layers = header.realObserSec.iLiTiSaoMiaoCengShu; // 层数
            int[] Records = new int[Layers];    //每层的径向数
            double[] MaxV = new double[Layers];  //每层的最大可测速度
            int Bins = 0;   // 各层的最大可测距离 单位：10 米
            for (int i = 0; i < Layers; i++) {
                Records[i] = header.realObserSec.LayerParam[i].iCaiYangJinXiangShu;  //每层采样的径向数
                this.Bins = header.realObserSec.LayerParam[i].usRefBinNumber;        //各层的最大可测距离 单位：10 米
                MaxV[i] = (double) (int) header.realObserSec.LayerParam[i].iZuiDaCeSu / 100.0;   //各层的最大可测速度；单位：厘米/秒
                this.BinLength = header.realObserSec.LayerParam[i].iKuChang;
            }

            azi = new double[Records[0]]; //第1层径向数作为数组的长度
            data = new double[Records[0]][this.Bins];   //
            int max = Arrays.stream(Records).max().getAsInt();

//            if (productType == ProductType.STIParser) {
//                //todo ---
//                ProductType sti  = STIParser.productType(this.bytes , index );  //index 1266
//            }
            if (productType == ProductType.VIL) {
                new VILParse(this).parse(bytes, index);
            }
            if (productType == ProductType.OHP) {
                // 一小时降水
                new OHPParse(this).parse(bytes, index);
            }
            if (productType == ProductType.CAPPI) {
                new CAPPIParse(this).parse(bytes, index, header);
            }
            if (productType == ProductType.RCS) {
                new RSCAndVCSparse(this).parse(bytes, index, header);
            }
            if (productType == ProductType.VCS) {
                new RSCAndVCSparse(this).parse(bytes, index, header);
            }
            if (productType == ProductType.RVD) {
                new RVDAndARDParser(this).parse(bytes, index, header);
            }
            if (productType == ProductType.ARD) {
                new RVDAndARDParser(this).parse(bytes, index, header);
            }
            if (productType == ProductType.VAD) {
                new VADParse(this).parse(bytes, index, header);
            }
            if (productType == ProductType.CS) {
                new CSParser(this).parse(bytes, index, header);
            }
            if (productType == ProductType.LRM) {
                new LRMParse(this).parse(bytes, index, header);
            }
            if (productType == ProductType.LRA) {
                new LRAParse(this).parse(bytes, index, header);
            }
            if (productType == ProductType.VWP) {
                new VWPParser(this).parse(bytes, index, header);
            }
            if (productType == ProductType.STI) {
                new STIParser(this).parse(bytes, index, header);
            }


            if (productType == ProductType.CR || productType == ProductType.REF || productType == ProductType.VEL || productType == ProductType.SW || productType == ProductType.ET || productType == ProductType.EB) {
                for (int i = 0; i < Records[0]; i++) {
                    // header
                    if (productType == ProductType.CR || productType == ProductType.REF || productType == ProductType.VEL || productType == ProductType.SW) {
                        RadialHeader radialHeader = new RadialHeader();
                        bytdata = new byte[radialHeader.len];
                        System.arraycopy(bytes, index, bytdata, 0, bytdata.length);
                        radialHeader.parse(bytdata);
                        ele = radialHeader.elevation;
                        index += bytdata.length;
                        azi[i] = radialHeader.azimuth;
                        for (int k = 0; k < this.Bins; k++) {
                            double d = (0xff & bytes[index]);
                            index += 1;
                            if (productType == ProductType.VEL) {
//                                this.data[i][k] = d == 0 ? GisConstants.UNDEF : (double) ((d - 128)) * 0.5;
//                                this.data[i][k] = d == 0 || d == 1 ? GisConstants.UNDEF : (double) ((d - 129)) * 0.5;
                                this.data[i][k] = d == 0 || d == 1 ? GisConstants.UNDEF : d;
//                                this.data[i][k] = d == 0 || d == 1 ? GisConstants.UNDEF : d;
                            } else if (productType == ProductType.SW) {
//                                this.data[i][k] = d == 0 || d == 1 ? GisConstants.UNDEF : (double) ((d - 129.0) * 0.5);
                                this.data[i][k] = d == 0 || d == 1 ? GisConstants.UNDEF : d;
                            } else {
//                                this.data[i][k] = (double) ((d - 66)) * 0.5;
                                this.data[i][k] = d == 0 || d == 1 ? GisConstants.UNDEF : d;
//                                this.data[i][k] = this.data[i][k] < -10 ? GisConstants.UNDEF : this.data[i][k];
                            }
                        }
                    }
                    if (productType == ProductType.ET || productType == ProductType.EB) {
                        RadialHeader radialHeader = new RadialHeader();
                        bytdata = new byte[radialHeader.len];
                        System.arraycopy(bytes, index, bytdata, 0, bytdata.length);
                        radialHeader.parse(bytdata);
                        index += bytdata.length;
                        azi[i] = radialHeader.azimuth;
                        for (int k = 0; k < this.Bins; k++) {
                            double d = Short.toUnsignedInt(BitConverter.toShort16(bytes, index));
                            index += 2;
//                            if (d<0){
//                                d=  GisConstants.UNDEF;
//                            }
                            this.data[i][k] = d / 100;
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return productType;
    }

    public RadarGridData project(ProductType productType) {
        ProductType t = productType == ProductType.CR || productType == ProductType.REF ? ProductType.CR : ProductType.VEL;
        byte[][] refs = MathCommon.Code(this.data, t);
        byte[][] gridppi = Cacl.gridppi(azi, refs, t);
        double resoultion = this.BinLength / 1000.0;
        RadarGridData project = Cacl.project(gridppi, 0, this.lon, this.lat, resoultion, 0.01);
        return project;
    }

    public RadarGridData projectNoZip() {
//        ProductType t = productType == ProductType.CR || productType == ProductType.REF ? ProductType.CR : ProductType.VEL;
        double[][] gridppi = Cacl.gridppi(azi, this.data, null);
        double resoultion = this.BinLength / 1000.0;
        RadarGridData project = Cacl.project(gridppi, 0, this.lon, this.lat, resoultion, 0.01);
        return project;
    }

//    public RadarGridData projectNoZip() {
////        ProductType t = productType == ProductType.CR || productType == ProductType.REF ? ProductType.CR : ProductType.VEL;
//        double[][] gridppi = Cacl.gridppi(azi, this.data, null);
//        RadarGridData project = new RadarGridData();
//        project.data = gridppi;
//        return project;
//    }

    public RadarGridData project3D(ProductType productType, int index) {
        ProductType t = productType == ProductType.CR || productType == ProductType.REF ? ProductType.CR : ProductType.VEL;
        double[][] refs = this.data3d[index];
        double[][] gridppi = Cacl.gridppi(azi, refs, t);
        double resoultion = this.BinLength / 1000.0;
        RadarGridData project = Cacl.project(gridppi, 0, this.lon, this.lat, resoultion, 0.01);
        return project;
    }

    public static void main(String[] args) throws RadarVisualizeError, RadarCaclError, IOException, RadarDecodeError {
        BufferedImage bufferedImage;
//        String f = "Z:\\radar\\20240129\\R\\20240129_202312.00.003.005.50.S.bz2";
        String f = "/Users/xx/Desktop/20240223/VIL/20240223_100916.00.025.005.0.2.0.S.bz2";
        Product382改 product346 = new Product382改();


//        System.out.println(++ i);
//        CinradRadar cinradRadar = new CinradRadar();
//        cinradRadar.parse("/Users/xx/DeskTop/346F/LD20180428111124005.VT346", CinradType.RADAR_382);

        ProductType productType = product346.parseProduct(f);
        System.out.println(productType.name());
//        bufferedImage = new PolarMap(null).simplePolarProduct346(PolarMap.buildPolarInfo(0, null).backColor(ThematicMap.nullColor), product346.data, product346.azi, "VIL");
//        bufferedImage = new RasterMap(null).drawSingleRaster(product346.projectNoZip().data, "ET" , ThematicMap.nullColor);
        bufferedImage = new RasterMap(null).drawSingleRaster(product346.data, "VIL", new Color(0, 0, 0, 0));
        ImageIO.write(bufferedImage, "png", new File(f + ".png"));

//         合成切变  单位 E-4/S
//        RadarGridData project = product346.projectNoZip();
//        RasterMap rasterMap = new RasterMap(null);
//        bufferedImage = rasterMap.drawSingleRaster(project.data, ProductType.SW, new Color(0, 0, 0, 0));

//        RadarGridData project = product346.project(ProductType.REF);
//        RadarGridData project = product346.project3D(ProductType.REF,0);

//        BufferedImage bufferedImage = rasterMap.drawSingleRaster(MathCommon.decode(project.radarData, ProductType.SW), ProductType.ET, new Color(0, 0, 0, 0));
//        BufferedImage bufferedImage = rasterMap.drawSingleRaster(product346.data3d[0], ProductType.REF, new Color(0, 0, 0, 0));
//        BufferedImage bufferedImage2 = rasterMap.drawSingleRaster(product346.data3d[1], ProductType.REF, new Color(0, 0, 0, 0));
//        BufferedImage bufferedImage3 = rasterMap.drawSingleRaster(product346.data3d[2], ProductType.REF, new Color(0, 0, 0, 0));

//
//        BufferedImage bufferedImage = rasterMap.drawSingleRaster(MathCommon.decode(project.radarData, ProductType.REF),
//                ProductType.REF, new Color(0, 0, 0, 0));


//        BufferedImage bufferedImage = rasterMap.drawSingleRaster(project.data, ProductType.VEL);
//        BufferedImage bufferedImage1 = rasterMap.drawSingleRaster(product346.lrmData1, ProductType.RVD);
//        BufferedImage bufferedImage2 = rasterMap.drawSingleRaster(product346.lrmData2, ProductType.RVD);
//        BufferedImage bufferedImage3 = rasterMap.drawSingleRaster(product346.lrmData3, ProductType.RVD);


//        ImageIO.write(bufferedImage2, "png", new File(f + ".2.png"));
//        ImageIO.write(bufferedImage3, "png", new File(f + ".3.png"));
//
//        PolarMap polarMap = new PolarMap(null);
//        BufferedImage bufferedImage = polarMap.simplePolar(PolarMap.buildPolarInfo(0, ProductType.SW));
//        BufferedImage bufferedImage =
//                polarMap.simplePolarProduct(
//                        PolarMap.buildPolarInfo(0, ProductType.CR)
//                                .backColor(new Color(0, 0, 0, 0))
//                        , product346.data, product346.azi);
//        ImageIO.write(bufferedImage2, "png", new File(f + "2.png"));
//        ImageIO.write(bufferedImage3, "png", new File(f + "3.png"));
//        MyNcUtil.readrToImageSave2(product346.data,"ws.lgs","D:\\work\\guorong\\国天资料\\20231111\\R","lraData1","png");
//        MyNcUtil.readrToImageSave2(product346.data3d[1],"radr.lgs","D:\\work\\guorong\\国天资料\\20231111\\LRA","lraData2","png");
//        MyNcUtil.readrToImageSave2(product346.data3d[2],"radr.lgs","D:\\work\\guorong\\国天资料\\20231111\\LRA","lraData3","png");


    }
}
